package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.AlertDataMapper;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.service.IAlertRuleService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 报警规则Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-01-17
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper,AlertRule> implements IAlertRuleService
{
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private IAlertDataService alertDataService;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 查询报警规则
     * 
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询报警规则列表
     * 
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
    {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule)
    {
        return save(alertRule)?1:0;
    }

    /**
     * 修改报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule)
    {
        return updateById(alertRule)?1:0;
    }

    /**
     * 批量删除报警规则
     * 
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids))?1:0;
    }

    /**
     * 删除报警规则信息
     * 
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id)
    {
        return removeById(id)?1:0;
    }

    @Override
    public void deviceDataAlertJob() {
        // 获取所有报警规则数量
        long count = this.count(new LambdaQueryWrapper<AlertRule>().eq(AlertRule::getStatus, 1));
        if (count < 1) {
            return;
        }
        // 获取所有设备上报的数据
        List<Object> values = redisTemplate.opsForHash().values("iot:device_last_data");
        if (CollUtil.isEmpty(values)){
            return;
        }

        List<DeviceData> deviceDataList = new ArrayList<>();
        values.forEach(value -> {
            List<DeviceData> list = JSONUtil.toList(value.toString(), DeviceData.class);
            deviceDataList.addAll(list);
        });
        // 遍历所有上报数据匹配报警规则
        deviceDataList.forEach(deviceData -> {
            alertRuleData(deviceData);
        });
    }

    private void alertRuleData(DeviceData deviceData) {
        // 查询所有的关联设备的规则
        List<AlertRule> allAlertRuleList = this.list(
                new LambdaQueryWrapper<AlertRule>()
                        .eq(AlertRule::getProductKey,  deviceData.getProductKey())
                        .eq(AlertRule::getFunctionId,  deviceData.getFunctionId())
                        .eq(AlertRule::getIotId, -1)
                        .eq(AlertRule::getStatus, 1)
        );
        // 获取某个设备的规则
        List<AlertRule> iotDevicealertRuleList = this.list(
                new LambdaQueryWrapper<AlertRule>()
                        .eq(AlertRule::getProductKey,  deviceData.getProductKey())
                        .eq(AlertRule::getFunctionId,  deviceData.getFunctionId())
                        .eq(AlertRule::getIotId, deviceData.getIotId())
                        .eq(AlertRule::getStatus, 1)
        );
        // 合并所有设备数据满足规则
        allAlertRuleList.addAll(iotDevicealertRuleList);
        if (CollUtil.isEmpty(allAlertRuleList)){
            return;
        }
        // 用设备数据匹配报警规则    遍历每条规则
        allAlertRuleList.forEach(alertRule -> {
            alertRuleMatchData(alertRule, deviceData);
        });
    }

    private void alertRuleMatchData(AlertRule alertRule, DeviceData deviceData) {
        // 校验数据时间是否在报警规则生效时间内
        LocalTime time = deviceData.getAlarmTime().toLocalTime();
        // 00：00：00-23：59：59
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime startTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        if (!time.isAfter(startTime) || !time.isBefore(endTime)){
            return;
        }
        // 校验数据是否达到阈值
        Double deviceValue = Double.valueOf(deviceData.getDataValue());
        Double ruleValue = alertRule.getValue();
        // 前 > 后 = 1 后 < 前 = -1 前 = 后 = 0
        int compare = CompareUtil.compare(deviceValue, ruleValue);
        if ((alertRule.getOperator().equals(">=") && compare >= 0)
                || (alertRule.getOperator().equals("<") && compare < 0))
        {
            log.info("符合报警规则");
        }
        else {
            // 删除报警数
            redisTemplate.delete("iot:silent:"
                    + deviceData.getIotId() + ":"
                    + deviceData.getFunctionId() + ":"
                    + alertRule.getId());
            return;
        }
        // 判断沉默周期
        String silent = redisTemplate.opsForValue().get("iot:silent:"
                + deviceData.getIotId() + ":"
                + deviceData.getFunctionId() + ":"
                + alertRule.getId()
        );
        if (ObjectUtil.isNotEmpty(silent)){
            return;
        }
        // 获取持续周期中的报警数
        String count = redisTemplate.opsForValue().get("iot:duration:"
                +  deviceData.getIotId()+  ":"
                +  deviceData.getFunctionId()+ ":"
                +  alertRule.getId());
        // 第一次算一次  不是就 +1
        int sum = count == null ? 1 : Integer.parseInt(count) + 1;
        if (!alertRule.getDuration().equals(sum)){
            redisTemplate.opsForValue().set("iot:duration:"
                    +  deviceData.getIotId()+  ":"
                    +  deviceData.getFunctionId()+ ":"
                    +  alertRule.getId(),
                    String.valueOf(sum));
            return;
        }
        // 所有规则都满足 才发送报警 删除计数
        redisTemplate.delete("iot:silent:"
                + deviceData.getIotId() + ":"
                + deviceData.getFunctionId() + ":"
                + alertRule.getId());

        // 添加沉默周期
        redisTemplate.opsForValue().set("iot:silent:"
                + deviceData.getIotId() + ":"
                + deviceData.getFunctionId() + ":"
                + alertRule.getId()
                ,"任意值无实际意义"
                ,alertRule.getAlertSilentPeriod()
                , TimeUnit.MINUTES);

        // 校验完成  发送报警
        List<Long> userIds = null;
        if (alertRule.getAlertDataType() == 0){
            // 老人异常数据
            if (deviceData.getLocationType().equals(0)){
                // 随身设备
                userIds = deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());

            }else {
                // 老人的固定设备-----床
                userIds = deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
            }
        }
        else {
            // 设备异常数据 查询维修人员id
            userIds = deviceMapper.selectUserIdByRoleName("维修工");
        }
        // 发送给超级管理员
        List<Long> managers  = deviceMapper.selectUserIdByRoleName("超级管理员");
        // 合并
        Collection<Long> longs = CollUtil.addAll(userIds, managers);
        ArrayList<Long> idList = CollUtil.distinct(longs);

        // 报警数据和用户插入数据库 并发送报警信息
        insertBatchRuleData(idList, alertRule, deviceData);
    }

    private void insertBatchRuleData(ArrayList<Long> idList, AlertRule alertRule, DeviceData deviceData) {
        AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
        alertData.setAlertRuleId(alertRule.getId());
        alertData.setAlertReason(alertRule.getFunctionName()
                +alertRule.getOperator()
                +alertRule.getValue()
                +",持续"+alertRule.getDuration()
                +"个周期就报警");
        alertData.setStatus(0);
        alertData.setType(alertRule.getAlertDataType());
        alertData.setCreateTime(new Date());
        alertData.setUpdateTime(new Date());
        alertData.setAccessLocation(deviceData.getRemark());
        List<AlertData> alertDataList = new ArrayList<>();
        idList.forEach(id -> {
            AlertData data = BeanUtil.toBean(alertData, AlertData.class);
            data.setId(null);
            data.setUserId(id);
            alertDataList.add(data);
        });
        alertDataService.saveBatch(alertDataList);
        // 推送消息 WebSocket
        AlertNotifyVo alertNotifyVo = new AlertNotifyVo();
        BeanUtil.toBean(alertDataList.get(0), AlertNotifyVo.class);
        alertNotifyVo.setFunctionName(alertRule.getFunctionName());
        alertNotifyVo.setAlertDataType(alertRule.getAlertDataType());
        alertNotifyVo.setNotifyType(1);
        webSocketServer.sendMessageToConsumer(alertNotifyVo, idList);
    }
}
